This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

library(spatstat)
library(sp)
library(rgeos)
library(maptools)
library(GISTools)
install.packages("tidyverse")
library(tmap)
library(sf)
library(geojsonio)
library(tmaptools)
library(tidyverse)
library(rgdal)
library(raster)
library(SciViews)
library(base)
library(broom)
library(spdep)
####Basemap
library(tmap)
BoroughMap <- geojson_read("https://raw.githubusercontent.com/ft-interactive/geo-data/master/uk/london/london-wards-2014.geojson", what = "sp")
BNG = "+init=epsg:27700"
BoroughMapBNG <- spTransform(BoroughMap,BNG)
WGS = "+init=epsg:4326"
tmap_mode("view")
tm_shape(BoroughMapBNG) +tm_polygons(col = NA, alpha = 0.5)

#aggregate city of london 
library(sf)
library(dplyr)
library(rgdal)
BoroughMapSF <- st_as_sf(BoroughMapBNG)
library(rgeos)
CityofLondon<- gUnionCascaded(BoroughMapBNG[c(630:654), ])
plot(CityofLondon)
CityofLondonSF <- st_as_sf(CityofLondon)
CityofLondonSF$gss_code_ward<-"E05000001"  ##add same columns in city of london, for aggregating with other borough
CityofLondonSF$gss_code_borough <- "E09000001"
CityofLondonSF$borough <-"City Of London"
CityofLondonSF$ward <- "City Of London"
BoroughMapSFnew <- BoroughMapSF[-c(630:654), ]
LondonWardSF <- rbind(BoroughMapSFnew,CityofLondonSF) ##Attention New not new
LondonWard <- as(LondonWardSF,"Spatial")
rownames(LondonWardSF) <- 1:nrow(LondonWardSF)
plot(LondonWard)
tm_shape(LondonWard) +tm_polygons(col = NA, alpha = 0.5)
####population density (using https://data.london.gov.uk/dataset/land-area-and-population-density-ward-and-borough 2016)
library(tidyverse)
Density <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/population_density_2016_final.csv",na = "n/a")
#normalization population_per_square_km
normalization<-function(x){
return((x-min(x))/(max(x)-min(x)))}
density.normalization <- normalization(Density$`population density`)
Density$Density.normalization <- density.normalization

#join the data to basemap P3P27
LondonWard.join.popdens <- LondonWardSF%>% left_join(Density,by=c("gss_code_ward"="New Code"))
qtm(LondonWard.join.popdens,fill="Density.normalization")
#### coexistence of old and new building
#read building list
building <- readOGR("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/Listed Buildings/ListedBuildings_06Dec2018.shp",layer="ListedBuildings_06Dec2018")

library(maptools)
LondonBoundary<-unionSpatialPolygons(LondonWard,gss_code_borough)
plot(LondonBoundary)
### Public transport accessibility level(PTAL)
PTAL <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/Ward2014 Avpublic transport accessibility level2015.csv",na = "n/a")
#normalization PTAL
normalization<-function(x){
return((x-min(x))/(max(x)-min(x)))}
PTAL.normalization <- normalization(PTAL$AvPTAI2015)
PTAL$PTAL.normalization <- PTAL.normalization
#join the data to basemap P3P27
LondonWard.join.PTAL <- LondonWardSF%>% left_join(PTAL,by=c("gss_code_ward"="Ward Code"))
qtm(LondonWard.join.PTAL,fill="PTAL.normalization")
qtm(LondonWard.join.PTAL,fill="AvPTAI2015")

###Public open space accessibility level(POSAL)
POSAL <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/access_public_open_space_ward.csv",na = "n/a")
POSAL$POSAL.normalization <- normalization(POSAL$`Open Space`)
LondonWard.join.POSAL <- LondonWardSF%>% left_join(POSAL,by=c("gss_code_ward"="WD13CD"))
#qtm(LondonWard.join.POSAL,fill="POSAL.normalization")
#combine two accessibility sub-index
Access.normalization<- merge(POSAL,PTAL, by.x="WD13CD",by.y="Ward Code",all=TRUE)
#remove useless column and rows
Access.normalization[,c(4:8,10:11)] <- NULL
#calculate the mean of two accessibility level
Access.normalization$access.mean <- rowMeans(Access.normalization[c('PTAL.normalization', 'POSAL.normalization')], na.rm=TRUE)

economic vitality

###economic vitality
#CLASS 1  house price
#HousePrice <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/house_price_mean2016.csv",na = "n/a")
#HousePrice.normalization <- normalization(HousePrice$Value)
#HousePrice$HousePrice.normalization <- HousePrice.normalization
#CLASS 2 economic activity
EcoAct <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/economic_activity_ward.csv",na = "n/a")
EcoAct.normalization <- normalization(EcoAct$`Economically active: Total`)
EcoAct$EcoAct.normalization <- EcoAct.normalization

land use mix

### Land use mix
#https://en.wikipedia.org/wiki/Planning_use_classes_in_England 
# six classes--
landcover <- readOGR("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/greater-london-latest-free.shp/gis_osm_landuse_a_free_1.shp",layer="gis_osm_landuse_a_free_1")
landcoverBNG <- spTransform(landcover, BNG)
landcoverBNGSF <- st_as_sf(landcoverBNG)

AOIS <- readOGR("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/greater-london-latest-free.shp/gis_osm_pois_a_free_1.shp",layer="gis_osm_pois_a_free_1")
AOISBNG <- spTransform(AOIS, BNG)
AOISBNGSF <- st_as_sf(AOISBNG)

#find missing data in each column in landcoverBNGSF
colSums(is.na(landcoverBNGSF))
#get the classes of landcover
summary(landcoverBNGSF)
#CLASS1 greenspace
greenspaceBNGSF <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="park" |  landcoverBNGSF$fclass =="forest"|landcoverBNGSF$fclass =="nature_reserve"|landcoverBNGSF$fclass =="grass"),] 
greenspaceBNGSP <- as(greenspaceBNGSF,"Spatial")
#CLASS2 industrial and commercial
industrialBNGSF <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="industrial"| landcoverBNGSF$fclass =="commercial"),]
industrialBNGSP <- as(industrialBNGSF,"Spatial")
#CLASS 3 residential
residentialBNGSF <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="residential" ),]
residentialBNGSP <- as(residentialBNGSF,"Spatial")
#CLASS 4 recreation-leisure
recreationBNGSF1 <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="recreation_ground"| landcoverBNGSF$fclass =="allotments"),]
recreationBNGSF2 <- AOISBNGSF[ which(AOISBNGSF$fclass =="attraction"|AOISBNGSF$fclass =="theatre"|AOISBNGSF$fclass =="arts_centre"),]
recreationBNGSF <- rbind(recreationBNGSF2,recreationBNGSF1)
recreationBNGSP <- as(recreationBNGSF,"Spatial")


#CLASS 5 retail
retailBNGSF1 <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="retail" ),]
retailBNGSF2 <- AOISBNGSF[ which( AOISBNGSF$fclass =="retail" ),]
retialBNGSF <- rbind(retailBNGSF2,retailBNGSF1)
retailBNGSP <- as(retailBNGSF,"Spatial")

#CLASS 6--community services
communityBNGSF <- AOISBNGSF[ which(AOISBNGSF$fclass =="school"|AOISBNGSF$fclass =="hospital"|AOISBNGSF$fclass =="nursing_home"|AOISBNGSF$fclass =="university"  ),]
communityBNGSP <- as(communityBNGSF,"Spatial")

#CLASS 7--transport
transport <- readOGR("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/greater-london-latest-free.shp/road_polygon_merge.shp",layer="road_polygon_merge")
transportBNG <- spTransform(transport, BNG)
transportBNG <- transportBNG[transportBNG@data$AREA >10000,] 
# Assign the land use area for each subset. Here we first use the most widespread residential as example 
library(raster)
r <- raster(ncols=400, nrows=400) #generate raster size(quantity)
extent(r) <- extent(residentialBNGSP)  #Important! Assign the extent of raster to cover the same extents of the polygon
residential.Raster <- rasterize(residentialBNGSP,r,background=NA) #convert polygon to raster
#tmap_mode("view")
#qtm(residential.Raster)+tm_shape(LondonWard) +tm_polygons(col = NA, alpha = 0.5)
#extract rasters from polygons#(extract() cannot use method=bilinear in raster-in-polygon)
residential.extract <- raster::extract(residential.Raster,LondonWard,df=TRUE, weights =FALSE, na.rm = TRUE)
#remove rows with NA
row.has.na <- apply(residential.extract, 1, function(x){any(is.na(x))})
residential.extract2 <-residential.extract[!row.has.na,]
#merge the pixel in same ward(aggregate the frequency of the same data in one)
library(plyr)
residential.extract.sum <- factor(residential.extract2$ID)  
residential.extract.sum <- table(residential.extract2$ID)
residential.extract.wardsum <- as.data.frame(residential.extract.sum)
#create new order number for LondonWardSF, for merge the residential.extract and LondonWardSF by order
LondonWard2SF <- LondonWardSF
LondonWard2SF$Var1 <- 1:630
LondonWard2SF[,'Var1']<-factor(LondonWard2SF[,'Var1'])
#merge two dataframe
residential.extract.final <- merge(residential.extract.wardsum, LondonWard2SF, by="Var1",all=TRUE)
#residential.extract.final [!duplicated(residential.extract.final ), ]
#replace NA values with 0
residential.extract.final[is.na(residential.extract.final)] <- 0
#rename the column
colnames(residential.extract.final)[2] <- "Freq.residential"
#raster cell size
#we have to convert raster to polygon because of raster(). This function only compute the pixel area in longitude/latitude coordiante system
residential.repolygon <- rasterToPolygons(residential.Raster, fun=NULL, n=4, na.rm=TRUE, digits=12, dissolve=TRUE)
#qtm(residential.repolygon)
residential.repolygonSF <- st_as_sf(residential.repolygon) 
residential.repolygonSF$area <- st_area(residential.repolygonSF)
#so the single pixel area is 28999.54 [m^2](0.029 km^2)

land use mix functions

##based on the details above, we create functions for land use analysis
function.raster <- function(landsp){
  extent(r) <- extent(landsp)
  landsp.Raster <- rasterize(landsp,r,background=NA)
  return(landsp.Raster)
}

function.extract<- function(landsp.Raster){
  landsp.extract <- raster::extract(landsp.Raster,LondonWard,df=TRUE, weights =FALSE, na.rm = TRUE)
  row.has.na <- apply(landsp.extract, 1, function(x){any(is.na(x))})
  landsp.extract2 <-landsp.extract[!row.has.na,]
  landsp.extract.sum <- factor(landsp.extract2$ID)  
  landsp.extract.sum <- table(landsp.extract2$ID)
  landsp.extract.wardsum <- as.data.frame(landsp.extract.sum)
  landsp.extract.final <- merge(landsp.extract.wardsum, LondonWard2SF, by="Var1",all=TRUE)
  landsp.extract.final[is.na(landsp.extract.final)] <- 0
  return(landsp.extract.final)
}
tmap_mode("view")
tmap mode set to interactive viewing
tm_shape(index.dataframeSP )+
    tm_polygons(c("Index", "MixIndex","Density.normalization","EcoAct.normalization","access.mean")) +
    tm_facets(sync = TRUE, ncol = 1,nrow=5,drop.empty.facets = F)
The number of facets exceeds the limit of 4. The limit can be extended to 5 with:
tmap_options(limits = c(facets.view = 5))

Test for the relationship

Linear regression model

qplot(PointPerSK,Index,data=node.index.frame,geom = "point") + stat_smooth(method="lm", se=FALSE, size=1)
#fit the linear model
model <- lm(PointPerSK ~ Index, data =node.index.frame)
#residual dataframe
library(broom)
model_res <- tidy(model)
summary(model)

Call:
lm(formula = PointPerSK ~ Index, data = node.index.frame)

Residuals:
    Min      1Q  Median      3Q     Max 
-61.603 -18.377  -3.996  13.130 231.436 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   15.872      3.324   4.775 2.24e-06 ***
Index        374.667     14.973  25.022  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 27.99 on 628 degrees of freedom
Multiple R-squared:  0.4992,    Adjusted R-squared:  0.4984 
F-statistic: 626.1 on 1 and 628 DF,  p-value: < 2.2e-16
plot(model)

The coefficient (estimate) in the summary() table shows that(on average) for a 1 unit (day) increase in unauthorised absence from school, there is a reduction in the average GCSE point score of -29.874.

The p-values for the intercept and the coefficient are highly statistically significant (<0.001) so we can rely on the relationship that is being observed.

The adjusted R-squared statistic is 0.38, which tells us that 38% of the variation in GCSE scores across Wards in London can be explained by variation in unauthorised absence from school (which is quite a lot for a single variable).

Interrogating the last graph in plot(model1)which is a scatter plot of fitted values (the model estimates achieved by plugging the values and coefficients back into the regression equation) against standardised residuals, we can see no apparent patterns in the cloud of points, which suggests the model has not violated any important assumptions.

Test for spatial patterns

we shoud test that is there any spatial clustering of residuals.If these places cluster in space, then there might be some unobserved underlying factor causing this. This is important is it means that the assumption of independence that regression models rely upon might be violated. Now in our case here, there is not a clear violation of spatial independence, but it is certainly hinted at. test for spatial patterns (spatial autocorrelation) using the Moran’s I statistic

### Test for spatial patterns (spatial autocorrelation) using the Moran's I statistic
#copy a new LondonWardSF
LondonWardSF.pattern <- LondonWardSF
LondonWardSF.pattern$model_resids <- model$residuals
LondonWardSF.pattern <- LondonWardSF.pattern[!(is.na(LondonWardSF.pattern$model_resids) ),]
LondonWardSP.pattern <- as(LondonWardSF.pattern,"Spatial")
tmap_mode("view")
qtm(LondonWardSF.pattern,fill='model_resids')
moran.test(LondonWardSP.pattern@data$model_resids, SpatialWeight,zero.policy=T)

    Moran I test under randomisation

data:  LondonWardSP.pattern@data$model_resids  
weights: SpatialWeight  n reduced by no-neighbour observations
  

Moran I statistic standard deviate = 3.1963, p-value = 0.0006961
alternative hypothesis: greater
sample estimates:
Moran I statistic       Expectation          Variance 
     0.0719958817     -0.0015923567      0.0005300699 

so here we have a statistically significant but relatively weak indication that there is some spatial clustering of residual values. A value of 0.07 (1 being perfect spatial autocorrelation, 0 being none at all) shows that there is no evidence that high residual values cluster near high values and low residual values cluster near lower values.

multi linear regression model

model_multi <- lm(PointPerSK ~ MixIndex+Density.normalization + access.mean + EcoAct.normalization, data = node.index.frame)
summary(model_multi)

Call:
lm(formula = PointPerSK ~ MixIndex + Density.normalization + 
    access.mean + EcoAct.normalization, data = node.index.frame)

Residuals:
    Min      1Q  Median      3Q     Max 
-62.704 -15.816  -3.713  12.011 218.380 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)           2.381e+01  6.546e+00   3.638 0.000298 ***
MixIndex              4.427e+07  1.951e+07   2.269 0.023615 *  
Density.normalization 1.506e+02  6.213e+00  24.245  < 2e-16 ***
access.mean           2.679e+01  7.021e+00   3.816 0.000149 ***
EcoAct.normalization  8.127e+00  6.392e+00   1.271 0.204039    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.27 on 625 degrees of freedom
Multiple R-squared:  0.5611,    Adjusted R-squared:  0.5583 
F-statistic: 199.8 on 4 and 625 DF,  p-value: < 2.2e-16
neighbour <- poly2nb(LondonWardSP.pattern,queen=T)
#create spatial weights object from these weights
SpatialWeight <- nb2listw(neighbour,style="C",zero.policy=T)
#Run moran I test
moran.test(LondonWardSP.pattern@data$model_resids_multi, SpatialWeight,zero.policy=T)

    Moran I test under randomisation

data:  LondonWardSP.pattern@data$model_resids_multi  
weights: SpatialWeight  n reduced by no-neighbour observations
  

Moran I statistic standard deviate = 2.1297, p-value = 0.0166
alternative hypothesis: greater
sample estimates:
Moran I statistic       Expectation          Variance 
     0.0473837384     -0.0015923567      0.0005288307 
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KYGBge3J9DQpsaWJyYXJ5KHNwYXRzdGF0KQ0KbGlicmFyeShzcCkNCmxpYnJhcnkocmdlb3MpDQpsaWJyYXJ5KG1hcHRvb2xzKQ0KbGlicmFyeShHSVNUb29scykNCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRtYXApDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShnZW9qc29uaW8pDQpsaWJyYXJ5KHRtYXB0b29scykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShTY2lWaWV3cykNCmxpYnJhcnkoYmFzZSkNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KHNwZGVwKQ0KYGBgDQoNCg0KYGBge3J9DQojIyMjQmFzZW1hcA0KbGlicmFyeSh0bWFwKQ0KQm9yb3VnaE1hcCA8LSBnZW9qc29uX3JlYWQoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9mdC1pbnRlcmFjdGl2ZS9nZW8tZGF0YS9tYXN0ZXIvdWsvbG9uZG9uL2xvbmRvbi13YXJkcy0yMDE0Lmdlb2pzb24iLCB3aGF0ID0gInNwIikNCkJORyA9ICIraW5pdD1lcHNnOjI3NzAwIg0KQm9yb3VnaE1hcEJORyA8LSBzcFRyYW5zZm9ybShCb3JvdWdoTWFwLEJORykNCldHUyA9ICIraW5pdD1lcHNnOjQzMjYiDQp0bWFwX21vZGUoInZpZXciKQ0KdG1fc2hhcGUoQm9yb3VnaE1hcEJORykgK3RtX3BvbHlnb25zKGNvbCA9IE5BLCBhbHBoYSA9IDAuNSkNCg0KI2FnZ3JlZ2F0ZSBjaXR5IG9mIGxvbmRvbiANCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShyZ2RhbCkNCkJvcm91Z2hNYXBTRiA8LSBzdF9hc19zZihCb3JvdWdoTWFwQk5HKQ0KbGlicmFyeShyZ2VvcykNCkNpdHlvZkxvbmRvbjwtIGdVbmlvbkNhc2NhZGVkKEJvcm91Z2hNYXBCTkdbYyg2MzA6NjU0KSwgXSkNCnBsb3QoQ2l0eW9mTG9uZG9uKQ0KQ2l0eW9mTG9uZG9uU0YgPC0gc3RfYXNfc2YoQ2l0eW9mTG9uZG9uKQ0KQ2l0eW9mTG9uZG9uU0YkZ3NzX2NvZGVfd2FyZDwtIkUwNTAwMDAwMSIgICMjYWRkIHNhbWUgY29sdW1ucyBpbiBjaXR5IG9mIGxvbmRvbiwgZm9yIGFnZ3JlZ2F0aW5nIHdpdGggb3RoZXIgYm9yb3VnaA0KQ2l0eW9mTG9uZG9uU0YkZ3NzX2NvZGVfYm9yb3VnaCA8LSAiRTA5MDAwMDAxIg0KQ2l0eW9mTG9uZG9uU0YkYm9yb3VnaCA8LSJDaXR5IE9mIExvbmRvbiINCkNpdHlvZkxvbmRvblNGJHdhcmQgPC0gIkNpdHkgT2YgTG9uZG9uIg0KQm9yb3VnaE1hcFNGbmV3IDwtIEJvcm91Z2hNYXBTRlstYyg2MzA6NjU0KSwgXQ0KTG9uZG9uV2FyZFNGIDwtIHJiaW5kKEJvcm91Z2hNYXBTRm5ldyxDaXR5b2ZMb25kb25TRikgIyNBdHRlbnRpb24gTmV3IG5vdCBuZXcNCkxvbmRvbldhcmQgPC0gYXMoTG9uZG9uV2FyZFNGLCJTcGF0aWFsIikNCnJvd25hbWVzKExvbmRvbldhcmRTRikgPC0gMTpucm93KExvbmRvbldhcmRTRikNCnBsb3QoTG9uZG9uV2FyZCkNCnRtX3NoYXBlKExvbmRvbldhcmQpICt0bV9wb2x5Z29ucyhjb2wgPSBOQSwgYWxwaGEgPSAwLjUpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KIyMjI3BvcHVsYXRpb24gZGVuc2l0eSAodXNpbmcgaHR0cHM6Ly9kYXRhLmxvbmRvbi5nb3YudWsvZGF0YXNldC9sYW5kLWFyZWEtYW5kLXBvcHVsYXRpb24tZGVuc2l0eS13YXJkLWFuZC1ib3JvdWdoIDIwMTYpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCkRlbnNpdHkgPC0gcmVhZF9jc3YoIkU6L1VDTC8wMDUtR0kgU3lzdGVtJlNjaWVuY2UvR0lTLUFzc2Vzc21lbnQgMy9SIGFzc2Vzc21lbnQzL3BvcHVsYXRpb25fZGVuc2l0eV8yMDE2X2ZpbmFsLmNzdiIsbmEgPSAibi9hIikNCiNub3JtYWxpemF0aW9uIHBvcHVsYXRpb25fcGVyX3NxdWFyZV9rbQ0Kbm9ybWFsaXphdGlvbjwtZnVuY3Rpb24oeCl7DQpyZXR1cm4oKHgtbWluKHgpKS8obWF4KHgpLW1pbih4KSkpfQ0KZGVuc2l0eS5ub3JtYWxpemF0aW9uIDwtIG5vcm1hbGl6YXRpb24oRGVuc2l0eSRgcG9wdWxhdGlvbiBkZW5zaXR5YCkNCkRlbnNpdHkkRGVuc2l0eS5ub3JtYWxpemF0aW9uIDwtIGRlbnNpdHkubm9ybWFsaXphdGlvbg0KDQojam9pbiB0aGUgZGF0YSB0byBiYXNlbWFwIFAzUDI3DQpMb25kb25XYXJkLmpvaW4ucG9wZGVucyA8LSBMb25kb25XYXJkU0YlPiUgbGVmdF9qb2luKERlbnNpdHksYnk9YygiZ3NzX2NvZGVfd2FyZCI9Ik5ldyBDb2RlIikpDQpxdG0oTG9uZG9uV2FyZC5qb2luLnBvcGRlbnMsZmlsbD0iRGVuc2l0eS5ub3JtYWxpemF0aW9uIikNCmBgYA0KDQpgYGB7cn0NCiMjIyMgY29leGlzdGVuY2Ugb2Ygb2xkIGFuZCBuZXcgYnVpbGRpbmcNCiNyZWFkIGJ1aWxkaW5nIGxpc3QNCmJ1aWxkaW5nIDwtIHJlYWRPR1IoIkU6L1VDTC8wMDUtR0kgU3lzdGVtJlNjaWVuY2UvR0lTLUFzc2Vzc21lbnQgMy9SIGFzc2Vzc21lbnQzL0xpc3RlZCBCdWlsZGluZ3MvTGlzdGVkQnVpbGRpbmdzXzA2RGVjMjAxOC5zaHAiLGxheWVyPSJMaXN0ZWRCdWlsZGluZ3NfMDZEZWMyMDE4IikNCg0KbGlicmFyeShtYXB0b29scykNCkxvbmRvbkJvdW5kYXJ5PC11bmlvblNwYXRpYWxQb2x5Z29ucyhMb25kb25XYXJkLGdzc19jb2RlX2Jvcm91Z2gpDQpwbG90KExvbmRvbkJvdW5kYXJ5KQ0KYGBgDQoNCmBgYHtyfQ0KIyMjIFB1YmxpYyB0cmFuc3BvcnQgYWNjZXNzaWJpbGl0eSBsZXZlbChQVEFMKQ0KUFRBTCA8LSByZWFkX2NzdigiRTovVUNMLzAwNS1HSSBTeXN0ZW0mU2NpZW5jZS9HSVMtQXNzZXNzbWVudCAzL1IgYXNzZXNzbWVudDMvV2FyZDIwMTQgQXZwdWJsaWMgdHJhbnNwb3J0IGFjY2Vzc2liaWxpdHkgbGV2ZWwyMDE1LmNzdiIsbmEgPSAibi9hIikNCiNub3JtYWxpemF0aW9uIFBUQUwNCm5vcm1hbGl6YXRpb248LWZ1bmN0aW9uKHgpew0KcmV0dXJuKCh4LW1pbih4KSkvKG1heCh4KS1taW4oeCkpKX0NClBUQUwubm9ybWFsaXphdGlvbiA8LSBub3JtYWxpemF0aW9uKFBUQUwkQXZQVEFJMjAxNSkNClBUQUwkUFRBTC5ub3JtYWxpemF0aW9uIDwtIFBUQUwubm9ybWFsaXphdGlvbg0KI2pvaW4gdGhlIGRhdGEgdG8gYmFzZW1hcCBQM1AyNw0KTG9uZG9uV2FyZC5qb2luLlBUQUwgPC0gTG9uZG9uV2FyZFNGJT4lIGxlZnRfam9pbihQVEFMLGJ5PWMoImdzc19jb2RlX3dhcmQiPSJXYXJkIENvZGUiKSkNCnF0bShMb25kb25XYXJkLmpvaW4uUFRBTCxmaWxsPSJQVEFMLm5vcm1hbGl6YXRpb24iKQ0KcXRtKExvbmRvbldhcmQuam9pbi5QVEFMLGZpbGw9IkF2UFRBSTIwMTUiKQ0KDQojIyNQdWJsaWMgb3BlbiBzcGFjZSBhY2Nlc3NpYmlsaXR5IGxldmVsKFBPU0FMKQ0KUE9TQUwgPC0gcmVhZF9jc3YoIkU6L1VDTC8wMDUtR0kgU3lzdGVtJlNjaWVuY2UvR0lTLUFzc2Vzc21lbnQgMy9SIGFzc2Vzc21lbnQzL2FjY2Vzc19wdWJsaWNfb3Blbl9zcGFjZV93YXJkLmNzdiIsbmEgPSAibi9hIikNClBPU0FMJFBPU0FMLm5vcm1hbGl6YXRpb24gPC0gbm9ybWFsaXphdGlvbihQT1NBTCRgT3BlbiBTcGFjZWApDQpMb25kb25XYXJkLmpvaW4uUE9TQUwgPC0gTG9uZG9uV2FyZFNGJT4lIGxlZnRfam9pbihQT1NBTCxieT1jKCJnc3NfY29kZV93YXJkIj0iV0QxM0NEIikpDQojcXRtKExvbmRvbldhcmQuam9pbi5QT1NBTCxmaWxsPSJQT1NBTC5ub3JtYWxpemF0aW9uIikNCiNjb21iaW5lIHR3byBhY2Nlc3NpYmlsaXR5IHN1Yi1pbmRleA0KQWNjZXNzLm5vcm1hbGl6YXRpb248LSBtZXJnZShQT1NBTCxQVEFMLCBieS54PSJXRDEzQ0QiLGJ5Lnk9IldhcmQgQ29kZSIsYWxsPVRSVUUpDQojcmVtb3ZlIHVzZWxlc3MgY29sdW1uIGFuZCByb3dzDQpBY2Nlc3Mubm9ybWFsaXphdGlvblssYyg0OjgsMTA6MTEpXSA8LSBOVUxMDQojY2FsY3VsYXRlIHRoZSBtZWFuIG9mIHR3byBhY2Nlc3NpYmlsaXR5IGxldmVsDQpBY2Nlc3Mubm9ybWFsaXphdGlvbiRhY2Nlc3MubWVhbiA8LSByb3dNZWFucyhBY2Nlc3Mubm9ybWFsaXphdGlvbltjKCdQVEFMLm5vcm1hbGl6YXRpb24nLCAnUE9TQUwubm9ybWFsaXphdGlvbicpXSwgbmEucm09VFJVRSkNCmBgYA0KDQpgYGB7cn0NCiMjIyBSb2FkIGludGVyc2VjdGlvbnMNCm5vZGUgPC0gcmVhZE9HUigiRTovVUNMLzAwNS1HSSBTeXN0ZW0mU2NpZW5jZS9HSVMtQXNzZXNzbWVudCAzL1IgYXNzZXNzbWVudDMvUm9hZCBOZXR3b3Jrb3Byb2FkX2Vzc2hfZ2IvbmV3X3JvYWRfbm9kZS5zaHAiLGxheWVyPSJuZXdfcm9hZF9ub2RlIikNCkJORyA9ICIraW5pdD1lcHNnOjI3NzAwIg0Kbm9kZUJORyA8LSBzcFRyYW5zZm9ybShub2RlLCBCTkcpDQpzdW1tYXJ5KG5vZGUpDQojI3F0bShub2RlQk5HKQ0Kbm9kZUJOR1NGIDwtIHN0X2FzX3NmKG5vZGVCTkcpDQojc2VsZWN0IHRoZSBub2RlIHR5cGUianVuY3Rpb24iDQpub2RlQk5HU0YgPC0gbm9kZUJOR1NGW3doaWNoKG5vZGVCTkdTRiRmb3JtT2ZOb2RlPT0ianVuY3Rpb24iKSxdDQpub2RlQk5HU1AgPC0gYXMobm9kZUJOR1NGLCAiU3BhdGlhbCIpDQpoZWFkKG5vZGUpDQojc2VsZWN0IG5vZGUgcG9pbnQgaW4gYm9yb3VnaA0Kbm9kZUJOR1NQIDwtIHJlbW92ZS5kdXBsaWNhdGVzKG5vZGVCTkdTUCkNCm5vZGVCTkdTUC5maW5hbDwtIG5vZGVCTkdTUFtMb25kb25XYXJkLF0NCiMgdG1hcCB2aWV3DQp0bWFwX21vZGUoInZpZXciKQ0KdG1fc2hhcGUoTG9uZG9uV2FyZCkgKw0KICB0bV9wb2x5Z29ucyhjb2wgPSBOQSwgYWxwaGEgPSAwLjUpICsNCnRtX3NoYXBlKG5vZGVCTkdTUC5maW5hbCkgKw0KICB0bV9kb3RzKGNvbCA9ICJibHVlIikNCg0KIyBjb3VudCBudW1iZXIgb2YgcG9pbnQgaW4gZWFjaCB3YXJkIA0KbGlicmFyeShHSVNUb29scykNCnBvbHkuY291bnRzKG5vZGVCTkdTUC5maW5hbCwgTG9uZG9uV2FyZCkgLT4gbm9kZWNvdW50DQojI3NldE5hbWVzKG5vZGVjb3VudCwgTG9uZG9uV2FyZEBkYXRhJG5vZGVjb3VudCkNCkxvbmRvbi5ub2RlIDwtIExvbmRvbldhcmRTRg0KTG9uZG9uLm5vZGUkbm9kZWNvdW50IDwtIG5vZGVjb3VudCAgICNhZGQgbnVtYmVyIG9mIHBvaW50IHRvIGVhY2ggd2FyZCAoTG9uZG9uLm5vZGUkbm9kZWNvdW50KQ0KI2NvbWJpbmUgdGhlIHdhcmQgYXJlYShzcSBrbSkNCkxvbmRvbi5ub2RlJFNxdWFyZV9LaWxvbWV0cmVzIDwtIExvbmRvbldhcmQuam9pbi5wb3BkZW5zJGBTcXVhcmUgS2lsb21ldHJlc2ANCiNjYWxjdWxhdGUgcG9pbnQvYXJlYS0tcG9pbnQgcGVyIHNxdWFyZSBraWxvbWV0cmUNCkxvbmRvbi5ub2RlJFBvaW50UGVyU0sgPC1Mb25kb24ubm9kZSRub2RlY291bnQvTG9uZG9uLm5vZGUkU3F1YXJlX0tpbG9tZXRyZXMNCnF0bShMb25kb24ubm9kZSxmaWxsPSJQb2ludFBlclNLIikNCiNqb2luIHdpdGggTG9uZG9uV2FyZFNGDQpMb25kb24ubm9kZVNGIDwtIGFwcGVuZF9kYXRhKExvbmRvbldhcmRTRixMb25kb24ubm9kZSwga2V5LnNocCA9ICJjb2RlIiwga2V5LmRhdGEgPSAiTmV3LmNvZGUiLCBpZ25vcmUuZHVwbGljYXRlcyA9IFRSVUUpDQpgYGANCg0KZWNvbm9taWMgdml0YWxpdHkNCmBgYHtyfQ0KIyMjZWNvbm9taWMgdml0YWxpdHkNCiNDTEFTUyAxICBob3VzZSBwcmljZQ0KI0hvdXNlUHJpY2UgPC0gcmVhZF9jc3YoIkU6L1VDTC8wMDUtR0kgU3lzdGVtJlNjaWVuY2UvR0lTLUFzc2Vzc21lbnQgMy9SIGFzc2Vzc21lbnQzL2hvdXNlX3ByaWNlX21lYW4yMDE2LmNzdiIsbmEgPSAibi9hIikNCiNIb3VzZVByaWNlLm5vcm1hbGl6YXRpb24gPC0gbm9ybWFsaXphdGlvbihIb3VzZVByaWNlJFZhbHVlKQ0KI0hvdXNlUHJpY2UkSG91c2VQcmljZS5ub3JtYWxpemF0aW9uIDwtIEhvdXNlUHJpY2Uubm9ybWFsaXphdGlvbg0KI0NMQVNTIDIgZWNvbm9taWMgYWN0aXZpdHkNCkVjb0FjdCA8LSByZWFkX2NzdigiRTovVUNMLzAwNS1HSSBTeXN0ZW0mU2NpZW5jZS9HSVMtQXNzZXNzbWVudCAzL1IgYXNzZXNzbWVudDMvZWNvbm9taWNfYWN0aXZpdHlfd2FyZC5jc3YiLG5hID0gIm4vYSIpDQpFY29BY3Qubm9ybWFsaXphdGlvbiA8LSBub3JtYWxpemF0aW9uKEVjb0FjdCRgRWNvbm9taWNhbGx5IGFjdGl2ZTogVG90YWxgKQ0KRWNvQWN0JEVjb0FjdC5ub3JtYWxpemF0aW9uIDwtIEVjb0FjdC5ub3JtYWxpemF0aW9uDQoNCmBgYA0KDQpsYW5kIHVzZSBtaXgNCmBgYHtyfQ0KIyMjIExhbmQgdXNlIG1peA0KI2h0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BsYW5uaW5nX3VzZV9jbGFzc2VzX2luX0VuZ2xhbmQgDQojIHNpeCBjbGFzc2VzLS0NCmxhbmRjb3ZlciA8LSByZWFkT0dSKCJFOi9VQ0wvMDA1LUdJIFN5c3RlbSZTY2llbmNlL0dJUy1Bc3Nlc3NtZW50IDMvUiBhc3Nlc3NtZW50My9ncmVhdGVyLWxvbmRvbi1sYXRlc3QtZnJlZS5zaHAvZ2lzX29zbV9sYW5kdXNlX2FfZnJlZV8xLnNocCIsbGF5ZXI9Imdpc19vc21fbGFuZHVzZV9hX2ZyZWVfMSIpDQpsYW5kY292ZXJCTkcgPC0gc3BUcmFuc2Zvcm0obGFuZGNvdmVyLCBCTkcpDQpsYW5kY292ZXJCTkdTRiA8LSBzdF9hc19zZihsYW5kY292ZXJCTkcpDQoNCkFPSVMgPC0gcmVhZE9HUigiRTovVUNMLzAwNS1HSSBTeXN0ZW0mU2NpZW5jZS9HSVMtQXNzZXNzbWVudCAzL1IgYXNzZXNzbWVudDMvZ3JlYXRlci1sb25kb24tbGF0ZXN0LWZyZWUuc2hwL2dpc19vc21fcG9pc19hX2ZyZWVfMS5zaHAiLGxheWVyPSJnaXNfb3NtX3BvaXNfYV9mcmVlXzEiKQ0KQU9JU0JORyA8LSBzcFRyYW5zZm9ybShBT0lTLCBCTkcpDQpBT0lTQk5HU0YgPC0gc3RfYXNfc2YoQU9JU0JORykNCg0KI2ZpbmQgbWlzc2luZyBkYXRhIGluIGVhY2ggY29sdW1uIGluIGxhbmRjb3ZlckJOR1NGDQpjb2xTdW1zKGlzLm5hKGxhbmRjb3ZlckJOR1NGKSkNCiNnZXQgdGhlIGNsYXNzZXMgb2YgbGFuZGNvdmVyDQpzdW1tYXJ5KGxhbmRjb3ZlckJOR1NGKQ0KI0NMQVNTMSBncmVlbnNwYWNlDQpncmVlbnNwYWNlQk5HU0YgPC0gbGFuZGNvdmVyQk5HU0ZbIHdoaWNoKCBsYW5kY292ZXJCTkdTRiRmY2xhc3MgPT0icGFyayIgfCAgbGFuZGNvdmVyQk5HU0YkZmNsYXNzID09ImZvcmVzdCJ8bGFuZGNvdmVyQk5HU0YkZmNsYXNzID09Im5hdHVyZV9yZXNlcnZlInxsYW5kY292ZXJCTkdTRiRmY2xhc3MgPT0iZ3Jhc3MiKSxdIA0KZ3JlZW5zcGFjZUJOR1NQIDwtIGFzKGdyZWVuc3BhY2VCTkdTRiwiU3BhdGlhbCIpDQojQ0xBU1MyIGluZHVzdHJpYWwgYW5kIGNvbW1lcmNpYWwNCmluZHVzdHJpYWxCTkdTRiA8LSBsYW5kY292ZXJCTkdTRlsgd2hpY2goIGxhbmRjb3ZlckJOR1NGJGZjbGFzcyA9PSJpbmR1c3RyaWFsInwgbGFuZGNvdmVyQk5HU0YkZmNsYXNzID09ImNvbW1lcmNpYWwiKSxdDQppbmR1c3RyaWFsQk5HU1AgPC0gYXMoaW5kdXN0cmlhbEJOR1NGLCJTcGF0aWFsIikNCiNDTEFTUyAzIHJlc2lkZW50aWFsDQpyZXNpZGVudGlhbEJOR1NGIDwtIGxhbmRjb3ZlckJOR1NGWyB3aGljaCggbGFuZGNvdmVyQk5HU0YkZmNsYXNzID09InJlc2lkZW50aWFsIiApLF0NCnJlc2lkZW50aWFsQk5HU1AgPC0gYXMocmVzaWRlbnRpYWxCTkdTRiwiU3BhdGlhbCIpDQojQ0xBU1MgNCByZWNyZWF0aW9uLWxlaXN1cmUNCnJlY3JlYXRpb25CTkdTRjEgPC0gbGFuZGNvdmVyQk5HU0ZbIHdoaWNoKCBsYW5kY292ZXJCTkdTRiRmY2xhc3MgPT0icmVjcmVhdGlvbl9ncm91bmQifCBsYW5kY292ZXJCTkdTRiRmY2xhc3MgPT0iYWxsb3RtZW50cyIpLF0NCnJlY3JlYXRpb25CTkdTRjIgPC0gQU9JU0JOR1NGWyB3aGljaChBT0lTQk5HU0YkZmNsYXNzID09ImF0dHJhY3Rpb24ifEFPSVNCTkdTRiRmY2xhc3MgPT0idGhlYXRyZSJ8QU9JU0JOR1NGJGZjbGFzcyA9PSJhcnRzX2NlbnRyZSIpLF0NCnJlY3JlYXRpb25CTkdTRiA8LSByYmluZChyZWNyZWF0aW9uQk5HU0YyLHJlY3JlYXRpb25CTkdTRjEpDQpyZWNyZWF0aW9uQk5HU1AgPC0gYXMocmVjcmVhdGlvbkJOR1NGLCJTcGF0aWFsIikNCg0KDQojQ0xBU1MgNSByZXRhaWwNCnJldGFpbEJOR1NGMSA8LSBsYW5kY292ZXJCTkdTRlsgd2hpY2goIGxhbmRjb3ZlckJOR1NGJGZjbGFzcyA9PSJyZXRhaWwiICksXQ0KcmV0YWlsQk5HU0YyIDwtIEFPSVNCTkdTRlsgd2hpY2goIEFPSVNCTkdTRiRmY2xhc3MgPT0icmV0YWlsIiApLF0NCnJldGlhbEJOR1NGIDwtIHJiaW5kKHJldGFpbEJOR1NGMixyZXRhaWxCTkdTRjEpDQpyZXRhaWxCTkdTUCA8LSBhcyhyZXRhaWxCTkdTRiwiU3BhdGlhbCIpDQoNCiNDTEFTUyA2LS1jb21tdW5pdHkgc2VydmljZXMNCmNvbW11bml0eUJOR1NGIDwtIEFPSVNCTkdTRlsgd2hpY2goQU9JU0JOR1NGJGZjbGFzcyA9PSJzY2hvb2wifEFPSVNCTkdTRiRmY2xhc3MgPT0iaG9zcGl0YWwifEFPSVNCTkdTRiRmY2xhc3MgPT0ibnVyc2luZ19ob21lInxBT0lTQk5HU0YkZmNsYXNzID09InVuaXZlcnNpdHkiICApLF0NCmNvbW11bml0eUJOR1NQIDwtIGFzKGNvbW11bml0eUJOR1NGLCJTcGF0aWFsIikNCg0KI0NMQVNTIDctLXRyYW5zcG9ydA0KdHJhbnNwb3J0IDwtIHJlYWRPR1IoIkU6L1VDTC8wMDUtR0kgU3lzdGVtJlNjaWVuY2UvR0lTLUFzc2Vzc21lbnQgMy9SIGFzc2Vzc21lbnQzL2dyZWF0ZXItbG9uZG9uLWxhdGVzdC1mcmVlLnNocC9yb2FkX3BvbHlnb25fbWVyZ2Uuc2hwIixsYXllcj0icm9hZF9wb2x5Z29uX21lcmdlIikNCnRyYW5zcG9ydEJORyA8LSBzcFRyYW5zZm9ybSh0cmFuc3BvcnQsIEJORykNCnRyYW5zcG9ydEJORyA8LSB0cmFuc3BvcnRCTkdbdHJhbnNwb3J0Qk5HQGRhdGEkQVJFQSA+MTAwMDAsXSANCg0KDQpgYGANCg0KYGBge3J9DQojIEFzc2lnbiB0aGUgbGFuZCB1c2UgYXJlYSBmb3IgZWFjaCBzdWJzZXQuIEhlcmUgd2UgZmlyc3QgdXNlIHRoZSBtb3N0IHdpZGVzcHJlYWQgcmVzaWRlbnRpYWwgYXMgZXhhbXBsZSANCmxpYnJhcnkocmFzdGVyKQ0KciA8LSByYXN0ZXIobmNvbHM9NDAwLCBucm93cz00MDApICNnZW5lcmF0ZSByYXN0ZXIgc2l6ZShxdWFudGl0eSkNCmV4dGVudChyKSA8LSBleHRlbnQocmVzaWRlbnRpYWxCTkdTUCkgICNJbXBvcnRhbnQhIEFzc2lnbiB0aGUgZXh0ZW50IG9mIHJhc3RlciB0byBjb3ZlciB0aGUgc2FtZSBleHRlbnRzIG9mIHRoZSBwb2x5Z29uDQpyZXNpZGVudGlhbC5SYXN0ZXIgPC0gcmFzdGVyaXplKHJlc2lkZW50aWFsQk5HU1AscixiYWNrZ3JvdW5kPU5BKSAjY29udmVydCBwb2x5Z29uIHRvIHJhc3Rlcg0KI3RtYXBfbW9kZSgidmlldyIpDQojcXRtKHJlc2lkZW50aWFsLlJhc3RlcikrdG1fc2hhcGUoTG9uZG9uV2FyZCkgK3RtX3BvbHlnb25zKGNvbCA9IE5BLCBhbHBoYSA9IDAuNSkNCiNleHRyYWN0IHJhc3RlcnMgZnJvbSBwb2x5Z29ucyMoZXh0cmFjdCgpIGNhbm5vdCB1c2UgbWV0aG9kPWJpbGluZWFyIGluIHJhc3Rlci1pbi1wb2x5Z29uKQ0KcmVzaWRlbnRpYWwuZXh0cmFjdCA8LSByYXN0ZXI6OmV4dHJhY3QocmVzaWRlbnRpYWwuUmFzdGVyLExvbmRvbldhcmQsZGY9VFJVRSwgd2VpZ2h0cyA9RkFMU0UsIG5hLnJtID0gVFJVRSkNCiNyZW1vdmUgcm93cyB3aXRoIE5BDQpyb3cuaGFzLm5hIDwtIGFwcGx5KHJlc2lkZW50aWFsLmV4dHJhY3QsIDEsIGZ1bmN0aW9uKHgpe2FueShpcy5uYSh4KSl9KQ0KcmVzaWRlbnRpYWwuZXh0cmFjdDIgPC1yZXNpZGVudGlhbC5leHRyYWN0WyFyb3cuaGFzLm5hLF0NCiNtZXJnZSB0aGUgcGl4ZWwgaW4gc2FtZSB3YXJkKGFnZ3JlZ2F0ZSB0aGUgZnJlcXVlbmN5IG9mIHRoZSBzYW1lIGRhdGEgaW4gb25lKQ0KbGlicmFyeShwbHlyKQ0KcmVzaWRlbnRpYWwuZXh0cmFjdC5zdW0gPC0gZmFjdG9yKHJlc2lkZW50aWFsLmV4dHJhY3QyJElEKSAgDQpyZXNpZGVudGlhbC5leHRyYWN0LnN1bSA8LSB0YWJsZShyZXNpZGVudGlhbC5leHRyYWN0MiRJRCkNCnJlc2lkZW50aWFsLmV4dHJhY3Qud2FyZHN1bSA8LSBhcy5kYXRhLmZyYW1lKHJlc2lkZW50aWFsLmV4dHJhY3Quc3VtKQ0KI2NyZWF0ZSBuZXcgb3JkZXIgbnVtYmVyIGZvciBMb25kb25XYXJkU0YsIGZvciBtZXJnZSB0aGUgcmVzaWRlbnRpYWwuZXh0cmFjdCBhbmQgTG9uZG9uV2FyZFNGIGJ5IG9yZGVyDQpMb25kb25XYXJkMlNGIDwtIExvbmRvbldhcmRTRg0KTG9uZG9uV2FyZDJTRiRWYXIxIDwtIDE6NjMwDQpMb25kb25XYXJkMlNGWywnVmFyMSddPC1mYWN0b3IoTG9uZG9uV2FyZDJTRlssJ1ZhcjEnXSkNCiNtZXJnZSB0d28gZGF0YWZyYW1lDQpyZXNpZGVudGlhbC5leHRyYWN0LmZpbmFsIDwtIG1lcmdlKHJlc2lkZW50aWFsLmV4dHJhY3Qud2FyZHN1bSwgTG9uZG9uV2FyZDJTRiwgYnk9IlZhcjEiLGFsbD1UUlVFKQ0KI3Jlc2lkZW50aWFsLmV4dHJhY3QuZmluYWwgWyFkdXBsaWNhdGVkKHJlc2lkZW50aWFsLmV4dHJhY3QuZmluYWwgKSwgXQ0KI3JlcGxhY2UgTkEgdmFsdWVzIHdpdGggMA0KcmVzaWRlbnRpYWwuZXh0cmFjdC5maW5hbFtpcy5uYShyZXNpZGVudGlhbC5leHRyYWN0LmZpbmFsKV0gPC0gMA0KI3JlbmFtZSB0aGUgY29sdW1uDQpjb2xuYW1lcyhyZXNpZGVudGlhbC5leHRyYWN0LmZpbmFsKVsyXSA8LSAiRnJlcS5yZXNpZGVudGlhbCINCiNyYXN0ZXIgY2VsbCBzaXplDQojd2UgaGF2ZSB0byBjb252ZXJ0IHJhc3RlciB0byBwb2x5Z29uIGJlY2F1c2Ugb2YgcmFzdGVyKCkuIFRoaXMgZnVuY3Rpb24gb25seSBjb21wdXRlIHRoZSBwaXhlbCBhcmVhIGluIGxvbmdpdHVkZS9sYXRpdHVkZSBjb29yZGlhbnRlIHN5c3RlbQ0KcmVzaWRlbnRpYWwucmVwb2x5Z29uIDwtIHJhc3RlclRvUG9seWdvbnMocmVzaWRlbnRpYWwuUmFzdGVyLCBmdW49TlVMTCwgbj00LCBuYS5ybT1UUlVFLCBkaWdpdHM9MTIsIGRpc3NvbHZlPVRSVUUpDQojcXRtKHJlc2lkZW50aWFsLnJlcG9seWdvbikNCnJlc2lkZW50aWFsLnJlcG9seWdvblNGIDwtIHN0X2FzX3NmKHJlc2lkZW50aWFsLnJlcG9seWdvbikgDQpyZXNpZGVudGlhbC5yZXBvbHlnb25TRiRhcmVhIDwtIHN0X2FyZWEocmVzaWRlbnRpYWwucmVwb2x5Z29uU0YpDQojc28gdGhlIHNpbmdsZSBwaXhlbCBhcmVhIGlzIDI4OTk5LjU0IFttXjJdKDAuMDI5IGttXjIpDQoNCmBgYA0KDQpsYW5kIHVzZSBtaXggZnVuY3Rpb25zDQpgYGB7cn0NCiMjYmFzZWQgb24gdGhlIGRldGFpbHMgYWJvdmUsIHdlIGNyZWF0ZSBmdW5jdGlvbnMgZm9yIGxhbmQgdXNlIGFuYWx5c2lzDQpmdW5jdGlvbi5yYXN0ZXIgPC0gZnVuY3Rpb24obGFuZHNwKXsNCiAgZXh0ZW50KHIpIDwtIGV4dGVudChsYW5kc3ApDQogIGxhbmRzcC5SYXN0ZXIgPC0gcmFzdGVyaXplKGxhbmRzcCxyLGJhY2tncm91bmQ9TkEpDQogIHJldHVybihsYW5kc3AuUmFzdGVyKQ0KfQ0KDQpmdW5jdGlvbi5leHRyYWN0PC0gZnVuY3Rpb24obGFuZHNwLlJhc3Rlcil7DQogIGxhbmRzcC5leHRyYWN0IDwtIHJhc3Rlcjo6ZXh0cmFjdChsYW5kc3AuUmFzdGVyLExvbmRvbldhcmQsZGY9VFJVRSwgd2VpZ2h0cyA9RkFMU0UsIG5hLnJtID0gVFJVRSkNCiAgcm93Lmhhcy5uYSA8LSBhcHBseShsYW5kc3AuZXh0cmFjdCwgMSwgZnVuY3Rpb24oeCl7YW55KGlzLm5hKHgpKX0pDQogIGxhbmRzcC5leHRyYWN0MiA8LWxhbmRzcC5leHRyYWN0WyFyb3cuaGFzLm5hLF0NCiAgbGFuZHNwLmV4dHJhY3Quc3VtIDwtIGZhY3RvcihsYW5kc3AuZXh0cmFjdDIkSUQpICANCiAgbGFuZHNwLmV4dHJhY3Quc3VtIDwtIHRhYmxlKGxhbmRzcC5leHRyYWN0MiRJRCkNCiAgbGFuZHNwLmV4dHJhY3Qud2FyZHN1bSA8LSBhcy5kYXRhLmZyYW1lKGxhbmRzcC5leHRyYWN0LnN1bSkNCiAgbGFuZHNwLmV4dHJhY3QuZmluYWwgPC0gbWVyZ2UobGFuZHNwLmV4dHJhY3Qud2FyZHN1bSwgTG9uZG9uV2FyZDJTRiwgYnk9IlZhcjEiLGFsbD1UUlVFKQ0KICBsYW5kc3AuZXh0cmFjdC5maW5hbFtpcy5uYShsYW5kc3AuZXh0cmFjdC5maW5hbCldIDwtIDANCiAgcmV0dXJuKGxhbmRzcC5leHRyYWN0LmZpbmFsKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KI2dyZWVuIHNwYWNlIHJhc3Rlcg0KZ3JlZW5zcGFjZS5SYXN0ZXIgPC0gZnVuY3Rpb24ucmFzdGVyKGdyZWVuc3BhY2VCTkdTUCkNCmdyZWVuc3BhY2UuZXh0cmFjdC5maW5hbCA8LSBmdW50aW9uLmV4dHJhY3QoZ3JlZW5zcGFjZS5SYXN0ZXIpDQpjb2xuYW1lcyhncmVlbnNwYWNlLmV4dHJhY3QuZmluYWwpWzJdIDwtICJGcmVxLmdyZWVuc3BhY2UiDQoNCiNpbmR1c3RyaWFsIGFuZCBjb21tZXJjaWFsDQppbmR1c3RyaWFsLlJhc3RlciA8LSBmdW5jdGlvbi5yYXN0ZXIoaW5kdXN0cmlhbEJOR1NQKQ0KaW5kdXN0cmlhbC5leHRyYWN0LmZpbmFsIDwtIGZ1bmN0aW9uLmV4dHJhY3QoaW5kdXN0cmlhbC5SYXN0ZXIpDQpjb2xuYW1lcyhpbmR1c3RyaWFsLmV4dHJhY3QuZmluYWwpWzJdIDwtICJGcmVxLmluZHVzdHJpYWwiDQojcmVjcmVhdGlvbg0KcmVjcmVhdGlvbi5SYXN0ZXIgPC0gZnVuY3Rpb24ucmFzdGVyKHJlY3JlYXRpb25CTkdTUCkNCnJlY3JlYXRpb24uZXh0cmFjdC5maW5hbCA8LSBmdW5jdGlvbi5leHRyYWN0KHJlY3JlYXRpb24uUmFzdGVyKQ0KY29sbmFtZXMocmVjcmVhdGlvbi5leHRyYWN0LmZpbmFsKVsyXSA8LSAiRnJlcS5yZWNyZWF0aW9uIg0KI3JldGFpbA0KcmV0YWlsLlJhc3RlciA8LSBmdW5jdGlvbi5yYXN0ZXIocmVjcmVhdGlvbkJOR1NQKQ0KcmV0YWlsLmV4dHJhY3QuZmluYWwgPC0gZnVuY3Rpb24uZXh0cmFjdChyZXRhaWwuUmFzdGVyKQ0KY29sbmFtZXMocmV0YWlsLmV4dHJhY3QuZmluYWwpWzJdIDwtICJGcmVxLnJldGFpbCINCiNjb21tdW5pdHkNCmNvbW11bml0eS5SYXN0ZXIgPC0gZnVuY3Rpb24ucmFzdGVyKGNvbW11bml0eUJOR1NQKQ0KY29tbXVuaXR5LmV4dHJhY3QuZmluYWwgPC0gZnVuY3Rpb24uZXh0cmFjdChjb21tdW5pdHkuUmFzdGVyKQ0KY29sbmFtZXMoY29tbXVuaXR5LmV4dHJhY3QuZmluYWwpWzJdIDwtICJGcmVxLmNvbW11bml0eSINCiN0cmFuc3BvcnQNCnRyYW5zcG9ydC5SYXN0ZXIgPC0gZnVuY3Rpb24ucmFzdGVyKHRyYW5zcG9ydEJORykNCnRyYW5zcG9ydC5leHRyYWN0LmZpbmFsIDwtIGZ1bmN0aW9uLmV4dHJhY3QodHJhbnNwb3J0LlJhc3RlcikNCmNvbG5hbWVzKHRyYW5zcG9ydC5leHRyYWN0LmZpbmFsKVsyXSA8LSAiRnJlcS50cmFuc3BvcnQiDQoNCnRtYXBfbW9kZSgidmlldyIpDQp0bV9zaGFwZShMb25kb25XYXJkKSArdG1fcG9seWdvbnMoY29sID0gTkEsIGFscGhhID0gMC4yKStxdG0ocmVjcmVhdGlvbi5SYXN0ZXIpDQojdG1fc2hhcGUoTG9uZG9uV2FyZCkgK3RtX3BvbHlnb25zKGNvbCA9IE5BLCBhbHBoYSA9IDAuMikrcXRtKHJlc2lkZW50aWFsLlJhc3RlcikNCg0KI2V4dHJhY3QgdXNlZnVsIGNvbHVtbnMgZnJvbSBtdWx0aXBsZSBkYXRhZnJhbWUNCmxhbmR1c2UuZGF0YWZyYW1lIDwtIHJlc2lkZW50aWFsLmV4dHJhY3QuZmluYWwNCmxhbmR1c2UuZGF0YWZyYW1lIDwtIG1lcmdlKGxhbmR1c2UuZGF0YWZyYW1lLGdyZWVuc3BhY2UuZXh0cmFjdC5maW5hbCwgYnk9IlZhcjEiLGFsbD1UUlVFKQ0KbGFuZHVzZS5kYXRhZnJhbWUgPC0gbWVyZ2UobGFuZHVzZS5kYXRhZnJhbWUsaW5kdXN0cmlhbC5leHRyYWN0LmZpbmFsLCBieT0iVmFyMSIsYWxsPVRSVUUpDQpsYW5kdXNlLmRhdGFmcmFtZSA8LSBtZXJnZShsYW5kdXNlLmRhdGFmcmFtZSxyZWNyZWF0aW9uLmV4dHJhY3QuZmluYWwsIGJ5PSJWYXIxIixhbGw9VFJVRSkNCmxhbmR1c2UuZGF0YWZyYW1lIDwtIG1lcmdlKGxhbmR1c2UuZGF0YWZyYW1lLHJldGFpbC5leHRyYWN0LmZpbmFsLCBieT0iVmFyMSIsYWxsPVRSVUUpDQpsYW5kdXNlLmRhdGFmcmFtZSA8LSBtZXJnZShsYW5kdXNlLmRhdGFmcmFtZSxjb21tdW5pdHkuZXh0cmFjdC5maW5hbCwgYnk9IlZhcjEiLGFsbD1UUlVFKQ0KbGFuZHVzZS5kYXRhZnJhbWUgPC0gbWVyZ2UobGFuZHVzZS5kYXRhZnJhbWUsdHJhbnNwb3J0LmV4dHJhY3QuZmluYWwsIGJ5PSJWYXIxIixhbGw9VFJVRSkNCmxhbmR1c2UuZGF0YWZyYW1lWyxjKDk6MTMsMTU6MTksMjE6MjUsMjc6MzEsMzM6MzcsMzk6NDMpXSA8LSBOVUxMICNyZW1vdmUgdXNlbGVzcyBjb2x1bW4NCmNvbG5hbWVzKGxhbmR1c2UuZGF0YWZyYW1lKVsyXSA8LSAicmVzaWRlbnRpYWwuZnJlcSIgI3JlbmFtZSBjb2x1bW4NCmhlYWQobGFuZHVzZS5kYXRhZnJhbWUpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KDQojY2FsY3VsYXRlIGVhY2ggd2FyZCBhcmVhDQpsYW5kdXNlLmRhdGFmcmFtZVNGIDwtbGVmdF9qb2luKExvbmRvbldhcmRTRixsYW5kdXNlLmRhdGFmcmFtZSxieT1jKCJnc3NfY29kZV93YXJkIj0iZ3NzX2NvZGVfd2FyZC54IikpDQpsYW5kdXNlLmRhdGFmcmFtZVNGJHdhcmRBcmVhIDwtIHN0X2FyZWEobGFuZHVzZS5kYXRhZnJhbWVTRikNCg0KbGlicmFyeShTY2lWaWV3cykNCmZ1bmN0aW9uLmxhbmR1c2VtaXggPC0gZnVuY3Rpb24obGFuZHVzZWZyZXEpew0KICBsYW5kdXNlYXJlYSA8LSBsYW5kdXNlZnJlcSooMC4wMjkqMC4wMjkpDQogIGxhbmR1c2VQZXJjZW50IDwtIGxhbmR1c2VhcmVhL2xhbmR1c2UuZGF0YWZyYW1lU0Ykd2FyZEFyZWENCiAgTFVNIDwtIGxhbmR1c2VQZXJjZW50KmxuKGxhbmR1c2VQZXJjZW50KQ0KICByZXR1cm4oTFVNKQ0KfQ0KDQpsYW5kdXNlLmRhdGFmcmFtZVNGJHJlc2lkZW50aWFsLkxVTSA8LSBmdW5jdGlvbi5sYW5kdXNlbWl4KGxhbmR1c2UuZGF0YWZyYW1lU0YkcmVzaWRlbnRpYWwuZnJlcSkNCmxhbmR1c2UuZGF0YWZyYW1lU0YkZ3JlZW5zcGFjZS5MVU0gPC0gZnVuY3Rpb24ubGFuZHVzZW1peChsYW5kdXNlLmRhdGFmcmFtZVNGJEZyZXEuZ3JlZW5zcGFjZSkNCmxhbmR1c2UuZGF0YWZyYW1lU0YkaW5kdXN0cmlhbC5MVU0gPC0gZnVuY3Rpb24ubGFuZHVzZW1peChsYW5kdXNlLmRhdGFmcmFtZVNGJEZyZXEuaW5kdXN0cmlhbCkNCmxhbmR1c2UuZGF0YWZyYW1lU0YkcmVjcmVhdGlvbi5MVU0gPC0gZnVuY3Rpb24ubGFuZHVzZW1peChsYW5kdXNlLmRhdGFmcmFtZVNGJEZyZXEucmVjcmVhdGlvbikNCmxhbmR1c2UuZGF0YWZyYW1lU0YkcmV0YWlsLkxVTSA8LSBmdW5jdGlvbi5sYW5kdXNlbWl4KGxhbmR1c2UuZGF0YWZyYW1lU0YkRnJlcS5yZXRhaWwpDQpsYW5kdXNlLmRhdGFmcmFtZVNGJGNvbW11bml0eS5MVU0gPC0gZnVuY3Rpb24ubGFuZHVzZW1peChsYW5kdXNlLmRhdGFmcmFtZVNGJEZyZXEuY29tbXVuaXR5KQ0KbGFuZHVzZS5kYXRhZnJhbWVTRiR0cmFuc3BvcnQuTFVNIDwtIGZ1bmN0aW9uLmxhbmR1c2VtaXgobGFuZHVzZS5kYXRhZnJhbWVTRiRGcmVxLnRyYW5zcG9ydCkNCmxpYnJhcnkoYmFzZSkNCiMjI3N1bSBsYW5kdXNlLkxVTSBhbmQgY2FsY3VsYXRlIGluZGV4DQppbmRleC5kYXRhZnJhbWU8LSBzdF9zZXRfZ2VvbWV0cnkobGFuZHVzZS5kYXRhZnJhbWVTRlssYygxOjYsMTg6MjUpXSxOVUxMKQ0KI3JlcGxhY2UgTkFOIHdpdGggMA0KaW5kZXguZGF0YWZyYW1lW2lzLm5hKGluZGV4LmRhdGFmcmFtZSldIDwtIDAgDQojIyNjb21wdXRlIGxhbmQgdXNlIG1peCBpbmRleA0KaW5kZXguZGF0YWZyYW1lJE1peEluZGV4IDwtIChhYnMocm93U3VtcyhpbmRleC5kYXRhZnJhbWVbLDg6MTRdKSkpL2xuKDcpDQoNCnF0bShpbmRleC5kYXRhZnJhbWVTRixmaWxsPSJNaXhJbmRleCIpDQpgYGANCg0KYGBge3J9DQoNCnF0bShyZXNpZGVudGlhbC5SYXN0ZXIpDQpsaWJyYXJ5KHRtYXApDQp0bWFwX21vZGUoInZpZXciKQ0KdG1fc2hhcGUoTG9uZG9uV2FyZCkgKw0KICB0bV9wb2x5Z29ucyhjb2wgPSBOQSwgYWxwaGEgPSAwLjUpICsNCnRtX3NoYXBlKHJlc2lkZW50aWFsQk5HU1ApICsNCiAgdG1fcG9seWdvbnMoY29sID0gImJsdWUiKQ0KYGBgDQoNCmBgYHtyfQ0KIyMjY29tYmluZSBhbGwgc3ViaW5kZXggDQppbmRleC5kYXRhZnJhbWUgPC0gbWVyZ2UoaW5kZXguZGF0YWZyYW1lLERlbnNpdHksYnkueD0iZ3NzX2NvZGVfd2FyZCIsYnkueT0iTmV3IENvZGUiLGFsbD1UUlVFKQ0KI2luZGV4LmRhdGFmcmFtZVssMzo3XSA8LSBOVUxMDQppbmRleC5kYXRhZnJhbWUgPC0gbWVyZ2UoaW5kZXguZGF0YWZyYW1lLEFjY2Vzcy5ub3JtYWxpemF0aW9uLCBieS54PSJnc3NfY29kZV93YXJkIixieS55PSJXRDEzQ0QiLGFsbD1UUlVFKQ0KaW5kZXguZGF0YWZyYW1lIDwtIG1lcmdlKGluZGV4LmRhdGFmcmFtZSxFY29BY3QsIGJ5Lng9Imdzc19jb2RlX3dhcmQiLGJ5Lnk9Ik5ldyBDb2RlIixhbGw9VFJVRSkNCmluZGV4LmRhdGFmcmFtZSA8LSBpbmRleC5kYXRhZnJhbWVbLGMoMTo0LDE1LDIwLDI1LDI5KV0NCiMjI2NhbGN1bGF0ZSB0aGUgZmluYWwgaW5kZXggb2Ygd2FyZHMsc2V0IHdlaWdodHMNCmZ1bmN0aW9uLnZpdGFsaXR5LmluZGV4IDwtIGZ1bmN0aW9uKHdMYW5kLHdEZW5zaXR5LHdBY2Nlc3Msd0Vjb0FjdCl7DQogIEluZGV4IDwtICh3TGFuZCkqKGluZGV4LmRhdGFmcmFtZVssNV0pKyh3RGVuc2l0eSkqKGluZGV4LmRhdGFmcmFtZVssNl0pKyh3QWNjZXNzKSooaW5kZXguZGF0YWZyYW1lWyw3XSkrKHdFY29BY3QpKihpbmRleC5kYXRhZnJhbWVbLDhdKQ0KICByZXR1cm4oSW5kZXgpDQp9DQojYXNzaWduIHdlaWdodCB0byBlYWNoIHN1YmluZGV4DQppbmRleC5kYXRhZnJhbWUkSW5kZXggPC0gZnVuY3Rpb24udml0YWxpdHkuaW5kZXgoMC40LDAuMywwLjIsMC4xKQ0KI2pvaW4gd2l0aCBMb25kb25XYXJkU0YgYW5kIHZpc3VhbGlzYXRpb24NCmluZGV4LmRhdGFmcmFtZVNGIDwtbGVmdF9qb2luKExvbmRvbldhcmRTRixpbmRleC5kYXRhZnJhbWUsYnk9YygiZ3NzX2NvZGVfd2FyZCI9Imdzc19jb2RlX3dhcmQiKSkNCmluZGV4LmRhdGFmcmFtZVNQIDwtIGFzKGluZGV4LmRhdGFmcmFtZVNGLCAiU3BhdGlhbCIpDQojY3JlYXRlIGluZGV4IGZhY2V0KHVzaW5nIHRtYXApDQp0bWFwX21vZGUoInZpZXciKQ0KdG1fc2hhcGUoaW5kZXguZGF0YWZyYW1lU1AgKSsNCiAgICB0bV9wb2x5Z29ucyhjKCJJbmRleCIsICJNaXhJbmRleCIsIkRlbnNpdHkubm9ybWFsaXphdGlvbiIsIkVjb0FjdC5ub3JtYWxpemF0aW9uIiwiYWNjZXNzLm1lYW4iKSkgKw0KICAgIHRtX2ZhY2V0cyhzeW5jID0gVFJVRSwgbmNvbCA9IDEsbnJvdz01LGRyb3AuZW1wdHkuZmFjZXRzID0gRikNCmBgYA0KDQojVGVzdCBmb3IgdGhlIHJlbGF0aW9uc2hpcA0KIyNMaW5lYXIgcmVncmVzc2lvbiBtb2RlbA0KDQpgYGB7cn0NCiMjI1NpbmNlIHdlIGhhdmUgZG9uZSB0aGUgbW9zdCBpbXBvcnRhbnQgcGFydCBvZiBkYXRhIG1hbmlwdWxhdGlvbiwgbmV4dCB3ZSB3aWxsIGV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGludGVyc2VjdGlvbiBhbmQgdml0YWxpdHkNCiNoaXN0b2dyYW0gb2YgdHdvIHZhcmlhYmxlcw0KcXBsb3QoUG9pbnRQZXJTSywgZGF0YSA9IExvbmRvbi5ub2RlLCBnZW9tID0gImhpc3RvZ3JhbSIpDQojZ2dwbG90KExvbmRvbi5ub2RlLCBhZXMoeD0iUG9pbnRQZXJTSyIsIHk9UG9pbnRQZXJTSykpK2dlb21fYm94cGxvdCgpIyh0aGlzIGlzIGFub3RoZXIgY29kZSBmb3IgYm94cGxvdCBpbiBnZ3Bsb3QyKQ0KI3FwbG90KHk9TG9uZG9uLm5vZGUkUG9pbnRQZXJTSywgeD0gMC4xLCBnZW9tID0gImJveHBsb3QiKSAgDQoNCnFwbG90KEluZGV4LCBkYXRhID0gaW5kZXguZGF0YWZyYW1lLCBnZW9tID0gImhpc3RvZ3JhbSIpDQojcXBsb3QoeT0gaW5kZXguZGF0YWZyYW1lJEluZGV4LCB4PSAwLjEsIGdlb20gPSAiYm94cGxvdCIpICANCg0KI3RoZSB2YXJpYWJsZXMgbG9vayBub3JtYWxseSBkaXN0cmlidXRlZCxidXQgd2Ugc2hvdWxkIGNvbnNpZGVyIHRoZSBvdXRsaWVycw0KcGxvdChMb25kb24ubm9kZSRQb2ludFBlclNLLGluZGV4LmRhdGFmcmFtZVNGJEluZGV4LGNvbD0iYmx1ZSIpDQojYWZ0ZXIgc2NhdHRlciBwbG90LCB3ZSBzaG91bGQgcmVtb3ZlICJMYWR5IE1hcmdhcmV0IiBhcyBpdHMgdW51c3VhbCByb2FkIGludGVyc2VjdGlvbiBkZW5zaXR5KG1heWJlIGR1ZSB0byB0aGUgcmVzaWRlbnRpYWwgcm9hZCBpbnRlcnNlY3Rpb25zIGFyZSBpbmNsdWRlZCkNCg0Kbm9kZS5pbmRleC5mcmFtZSA8LW1lcmdlKGluZGV4LmRhdGFmcmFtZSxMb25kb24ubm9kZSwgYnkueD0iZ3NzX2NvZGVfd2FyZCIsYnkueT0iZ3NzX2NvZGVfd2FyZCIsYWxsPVRSVUUpIA0KI3JlbW92ZSBvdXRsaWVyLS1MYWR5IE1hcmdhcmV0KEUwNTAwMDE4MSkNCiNub2RlLmluZGV4LmZyYW1lIDwtIG5vZGUuaW5kZXguZnJhbWVbbm9kZS5pbmRleC5mcmFtZSRQb2ludFBlclNLPDMwMCxdDQojbGluZWFyIHJlZ3Jlc3Npb24gcGxvdA0KcXBsb3QoUG9pbnRQZXJTSyxJbmRleCxkYXRhPW5vZGUuaW5kZXguZnJhbWUsZ2VvbSA9ICJwb2ludCIpICsgc3RhdF9zbW9vdGgobWV0aG9kPSJsbSIsIHNlPUZBTFNFLCBzaXplPTEpDQojZml0IHRoZSBsaW5lYXIgbW9kZWwNCm1vZGVsIDwtIGxtKFBvaW50UGVyU0sgfiBJbmRleCwgZGF0YSA9bm9kZS5pbmRleC5mcmFtZSkNCiNyZXNpZHVhbCBkYXRhZnJhbWUNCmxpYnJhcnkoYnJvb20pDQptb2RlbF9yZXMgPC0gdGlkeShtb2RlbCkNCnN1bW1hcnkobW9kZWwpDQpwbG90KG1vZGVsKQ0KDQoNCmBgYA0KDQpUaGUgY29lZmZpY2llbnQgKGVzdGltYXRlKSBpbiB0aGUgc3VtbWFyeSgpIHRhYmxlIHNob3dzIHRoYXQob24gYXZlcmFnZSkgZm9yIGEgMSB1bml0IChkYXkpIGluY3JlYXNlIGluIHVuYXV0aG9yaXNlZCBhYnNlbmNlIGZyb20gc2Nob29sLCB0aGVyZSBpcyBhIHJlZHVjdGlvbiBpbiB0aGUgYXZlcmFnZSBHQ1NFIHBvaW50IHNjb3JlIG9mIC0yOS44NzQuDQoNClRoZSBwLXZhbHVlcyBmb3IgdGhlIGludGVyY2VwdCBhbmQgdGhlIGNvZWZmaWNpZW50IGFyZSBoaWdobHkgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCAoPDAuMDAxKSBzbyB3ZSBjYW4gcmVseSBvbiB0aGUgcmVsYXRpb25zaGlwIHRoYXQgaXMgYmVpbmcgb2JzZXJ2ZWQuDQoNClRoZSBhZGp1c3RlZCBSLXNxdWFyZWQgc3RhdGlzdGljIGlzIDAuMzgsIHdoaWNoIHRlbGxzIHVzIHRoYXQgMzglIG9mIHRoZSB2YXJpYXRpb24gaW4gR0NTRSBzY29yZXMgYWNyb3NzIFdhcmRzIGluIExvbmRvbiBjYW4gYmUgZXhwbGFpbmVkIGJ5IHZhcmlhdGlvbiBpbiB1bmF1dGhvcmlzZWQgYWJzZW5jZSBmcm9tIHNjaG9vbCAod2hpY2ggaXMgcXVpdGUgYSBsb3QgZm9yIGEgc2luZ2xlIHZhcmlhYmxlKS4NCg0KSW50ZXJyb2dhdGluZyB0aGUgbGFzdCBncmFwaCBpbiBwbG90KG1vZGVsMSl3aGljaCBpcyBhIHNjYXR0ZXIgcGxvdCBvZiBmaXR0ZWQgdmFsdWVzICh0aGUgbW9kZWwgZXN0aW1hdGVzIGFjaGlldmVkIGJ5IHBsdWdnaW5nIHRoZSB2YWx1ZXMgYW5kIGNvZWZmaWNpZW50cyBiYWNrIGludG8gdGhlIHJlZ3Jlc3Npb24gZXF1YXRpb24pIGFnYWluc3Qgc3RhbmRhcmRpc2VkIHJlc2lkdWFscywgd2UgY2FuIHNlZSBubyBhcHBhcmVudCBwYXR0ZXJucyBpbiB0aGUgY2xvdWQgb2YgcG9pbnRzLCB3aGljaCBzdWdnZXN0cyB0aGUgbW9kZWwgaGFzIG5vdCB2aW9sYXRlZCBhbnkgaW1wb3J0YW50IGFzc3VtcHRpb25zLg0KDQojI1Rlc3QgZm9yIHNwYXRpYWwgcGF0dGVybnMNCndlIHNob3VkIHRlc3QgdGhhdCBpcyB0aGVyZSBhbnkgc3BhdGlhbCBjbHVzdGVyaW5nIG9mIHJlc2lkdWFscy5JZiB0aGVzZSBwbGFjZXMgY2x1c3RlciBpbiBzcGFjZSwgdGhlbiB0aGVyZSBtaWdodCBiZSBzb21lIHVub2JzZXJ2ZWQgdW5kZXJseWluZyBmYWN0b3IgY2F1c2luZyB0aGlzLiBUaGlzIGlzIGltcG9ydGFudCBpcyBpdCBtZWFucyB0aGF0IHRoZSBhc3N1bXB0aW9uIG9mIGluZGVwZW5kZW5jZSB0aGF0IHJlZ3Jlc3Npb24gbW9kZWxzIHJlbHkgdXBvbiBtaWdodCBiZSB2aW9sYXRlZC4NCk5vdyBpbiBvdXIgY2FzZSBoZXJlLCB0aGVyZSBpcyBub3QgYSBjbGVhciB2aW9sYXRpb24gb2Ygc3BhdGlhbCBpbmRlcGVuZGVuY2UsIGJ1dCBpdCBpcyBjZXJ0YWlubHkgaGludGVkIGF0Lg0KIHRlc3QgZm9yIHNwYXRpYWwgcGF0dGVybnMgKHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uKSB1c2luZyB0aGUgTW9yYW4ncyBJIHN0YXRpc3RpYw0KYGBge3J9DQojIyMgVGVzdCBmb3Igc3BhdGlhbCBwYXR0ZXJucyAoc3BhdGlhbCBhdXRvY29ycmVsYXRpb24pIHVzaW5nIHRoZSBNb3JhbidzIEkgc3RhdGlzdGljDQojY29weSBhIG5ldyBMb25kb25XYXJkU0YNCkxvbmRvbldhcmRTRi5wYXR0ZXJuIDwtIExvbmRvbldhcmRTRg0KTG9uZG9uV2FyZFNGLnBhdHRlcm4kbW9kZWxfcmVzaWRzIDwtIG1vZGVsJHJlc2lkdWFscw0KTG9uZG9uV2FyZFNGLnBhdHRlcm4gPC0gTG9uZG9uV2FyZFNGLnBhdHRlcm5bIShpcy5uYShMb25kb25XYXJkU0YucGF0dGVybiRtb2RlbF9yZXNpZHMpICksXQ0KTG9uZG9uV2FyZFNQLnBhdHRlcm4gPC0gYXMoTG9uZG9uV2FyZFNGLnBhdHRlcm4sIlNwYXRpYWwiKQ0KdG1hcF9tb2RlKCJ2aWV3IikNCnF0bShMb25kb25XYXJkU0YucGF0dGVybixmaWxsPSdtb2RlbF9yZXNpZHMnKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCiNsaWJyYXJ5KHNwZGVwKQ0KI0NhbGN1bGF0ZSB0aGUgY2VudHJvaWRzIG9mIExvbmRvbiB3YXJkcw0KY2VudFdhcmQgPC0gY29vcmRpbmF0ZXMoTG9uZG9uV2FyZFNQLnBhdHRlcm4pDQpwbG90KGNlbnRXYXJkKQ0KI0dlbmVyYXRlIHRoZSBzcGF0aWFsIHdlaWdodHMgbWF0cml4LHVzaW5nIGJpbmFyeSBtYXRyaXggb2YgcXVlZW4ncyBjYXNlIG5laWdoYm91cnMNCiNjcmVhdGUgbmVpZ2hib3VycyBsaXN0DQoNCmxpYnJhcnkoc3BkZXApDQpuZWlnaGJvdXIgPC0gcG9seTJuYihMb25kb25XYXJkU1AucGF0dGVybixxdWVlbj1UKQ0KI3Bsb3QNCnBsb3QobmVpZ2hib3VyLGNvb3JkaW5hdGVzKGNlbnRXYXJkKSxjb2w9InJlZCIpDQpwbG90KExvbmRvbldhcmRTUC5wYXR0ZXJuLGFkZD1UKQ0KI2NyZWF0ZSBzcGF0aWFsIHdlaWdodHMgb2JqZWN0IGZyb20gdGhlc2Ugd2VpZ2h0cw0KU3BhdGlhbFdlaWdodCA8LSBuYjJsaXN0dyhuZWlnaGJvdXIsc3R5bGU9IkMiLHplcm8ucG9saWN5PVQpDQojUnVuIG1vcmFuIEkgdGVzdA0KbW9yYW4udGVzdChMb25kb25XYXJkU1AucGF0dGVybkBkYXRhJG1vZGVsX3Jlc2lkcywgU3BhdGlhbFdlaWdodCx6ZXJvLnBvbGljeT1UKQ0KYGBgDQpzbyBoZXJlIHdlIGhhdmUgYSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGJ1dCByZWxhdGl2ZWx5IHdlYWsgaW5kaWNhdGlvbiB0aGF0IHRoZXJlIGlzIHNvbWUgc3BhdGlhbCBjbHVzdGVyaW5nIG9mIHJlc2lkdWFsIHZhbHVlcy4gQSB2YWx1ZSBvZiAwLjA3ICgxIGJlaW5nIHBlcmZlY3Qgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIDAgYmVpbmcgbm9uZSBhdCBhbGwpIHNob3dzIHRoYXQgdGhlcmUgaXMgbm8gZXZpZGVuY2UgdGhhdCBoaWdoIHJlc2lkdWFsIHZhbHVlcyBjbHVzdGVyIG5lYXIgaGlnaCB2YWx1ZXMgYW5kIGxvdyByZXNpZHVhbCB2YWx1ZXMgY2x1c3RlciBuZWFyIGxvd2VyIHZhbHVlcy4NCg0KDQojbXVsdGkgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwNCmBgYHtyfQ0KIyMjRm9yIGEgZGVlcGVyIHJlc2VhcmNoLCB3ZSB3aWxsIGJ1aWxkIGEgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdG8gZmluZCB3aGV0aGVyIHRoZSB1cmJhbiB2aXRhbGl0eSBpbmRleCBoYXMgYSByZWxhdGlvbnNoaXAgd2l0aCB1cmJhbiB2aXRhbGl0eSBzdWItZmFjdG9ycy4gSWYgc28sIHdoaWNoIG9uZSBpcyB0aGUgc3Ryb25nZXN0IG9yIHdlYWtlc3QuDQojDQpsaWJyYXJ5KGNvcnJwbG90KQ0KY29ybWF0IDwtIGNvcihub2RlLmluZGV4LmZyYW1lWyxjKDU6OCwxNildLCB1c2U9ImNvbXBsZXRlLm9icyIsIG1ldGhvZD0icGVhcnNvbiIpDQpjb3JycGxvdChjb3JtYXQpDQojclJ1biBtdWx0aXBsZSByZWdyZXNzaW9uIG1vZGVsDQptb2RlbF9tdWx0aSA8LSBsbShQb2ludFBlclNLIH4gTWl4SW5kZXgrRGVuc2l0eS5ub3JtYWxpemF0aW9uICsgYWNjZXNzLm1lYW4gKyBFY29BY3Qubm9ybWFsaXphdGlvbiwgZGF0YSA9IG5vZGUuaW5kZXguZnJhbWUpDQpzdW1tYXJ5KG1vZGVsX211bHRpKQ0KYGBgDQoNCmBgYHtyfQ0KIyNzYW1lIGFzIHJlc2lkdWFsIGF1dG9jb3JyZWxhdGlvbiBhbmFseXNpcyBhYm92ZQ0KbW9kZWxfcmVzX211bHRpIDwtIHRpZHkobW9kZWxfbXVsdGkpDQpwbG90KG1vZGVsX211bHRpKQ0KTG9uZG9uV2FyZFNGLnBhdHRlcm4kbW9kZWxfcmVzaWRzX211bHRpIDwtIG1vZGVsX211bHRpJHJlc2lkdWFscw0KTG9uZG9uV2FyZFNQLnBhdHRlcm4gPC0gYXMoTG9uZG9uV2FyZFNGLnBhdHRlcm4sIlNwYXRpYWwiKQ0KdG1hcF9tb2RlKCJ2aWV3IikNCnF0bShMb25kb25XYXJkU0YucGF0dGVybixmaWxsPSdtb2RlbF9yZXNpZHNfbXVsdGknKQ0KbGlicmFyeShzcGRlcCkNCm5laWdoYm91ciA8LSBwb2x5Mm5iKExvbmRvbldhcmRTUC5wYXR0ZXJuLHF1ZWVuPVQpDQojY3JlYXRlIHNwYXRpYWwgd2VpZ2h0cyBvYmplY3QgZnJvbSB0aGVzZSB3ZWlnaHRzDQpTcGF0aWFsV2VpZ2h0IDwtIG5iMmxpc3R3KG5laWdoYm91cixzdHlsZT0iQyIsemVyby5wb2xpY3k9VCkNCiNSdW4gbW9yYW4gSSB0ZXN0DQptb3Jhbi50ZXN0KExvbmRvbldhcmRTUC5wYXR0ZXJuQGRhdGEkbW9kZWxfcmVzaWRzX211bHRpLCBTcGF0aWFsV2VpZ2h0LHplcm8ucG9saWN5PVQpDQpgYGANCg0K